package com.dycong.common.IO.socket.NIO;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;

/**
 * Created by dycong on 2017/3/23.
 */
public class NIOClient {
    private static String HOST = "localhost";
    private static int DEFAULT_PORT = 12121;

    public NIOClient() {
    }

    public NIOClient(String host, Integer port) {
        HOST = host;
        DEFAULT_PORT = port;
    }

    public void start() {
        start(HOST, DEFAULT_PORT);
    }

    private final void start(String host, Integer port) {
        SocketChannel socketChannel = null;
        Selector selector = null;
        try {
            //todo 其实，Client的selector可以设为static线程共享，创建Selector可以加锁，双重校验锁机制,但是Client端的Socket显然没必要设为静态
            selector = Selector.open();
            socketChannel = SocketChannel.open();
            //todo important
            socketChannel.configureBlocking(false);
            //// TODO: 2017/3/25  bind()是用来绑定本地地址的
            //socketChannel.bind(new InetSocketAddress(host, port));
            socketChannel.connect(new InetSocketAddress(host, port));

            socketChannel.register(selector, SelectionKey.OP_CONNECT);
            while (true) {
                if (selector.select() == 0) continue;
                Iterator<SelectionKey> it = selector.selectedKeys().iterator();
                SocketChannel client = null;
                while (it.hasNext()) {
                    SelectionKey key = it.next();
                    if (key.isConnectable()) {
                        client = (SocketChannel) key.channel();
                        client.configureBlocking(false);
                        if (client.finishConnect()) {
                            ByteBuffer buffer = ByteBuffer.allocate(500);
                            buffer.put("hello server".getBytes());
                            buffer.flip();
                            client.write(buffer);
                            client.register(selector, SelectionKey.OP_READ);
//                            buffer.clear();
//                            client.read(buffer);
//                            buffer.flip();
//                            System.out.println(new String(buffer.array()));
                        } else {
                            try {
                                Thread.sleep(10L);
                            } catch (InterruptedException e) {
                                System.out.println(e);
                            }
                            if (client.finishConnect()) {
                                client.register(selector, SelectionKey.OP_READ);
                                ByteBuffer buffer = ByteBuffer.allocate(500);
                                buffer.put("hello server".getBytes());
                                buffer.flip();
                                client.write(buffer);
                            }
                        }
                        //todo 如果一个SocketChannel已经被register，再register时只会修改监听状态，不会重新register，所以不能cancel()
//                        key.cancel();
                    }
                    if (key.isReadable()) {
                        client=(SocketChannel) key.channel();
                        ByteBuffer buffer=ByteBuffer.allocate(1024);
                        client.read(buffer);
                        buffer.flip();
                        System.out.println("client:"+new String(buffer.array()));
                        ByteBuffer res=ByteBuffer.allocate(1024);
                        res.put(String.valueOf(System.currentTimeMillis()).getBytes());
                        client.write(res);
                        client.close();
                    }
                }

            }

        } catch (IOException e) {
            System.out.println("client start error: " + e);
        } finally {
            try {
                if (null != socketChannel) {
                    socketChannel.close();
                }
                if (null != selector) {
                    selector.close();
                }
            } catch (IOException e) {
                System.out.println("client close error: " + e);
            }
        }
    }
}
